/**
 +-------------------------------------------------------------------
 * Timer - 定时任务插件
 * 说明： 
 * 		本项目由konger123编写，用来提供比较方便的控制定时任务的启停、暂停等操作；
 * 		1.支持页面内的多个Timer分别独立控制（页面里Timer不要用太多，否则会比较占资源）；
 *		2.支持自由的对Timer进行【启动】、【停止】、【重置】、【暂停】、【继续】、【销毁】等控制方法；
 *		3.可以设置timer的运行次数(loop>0)，或者设置成无限循环模式(loop=-1)；
 * 		4.支持interval和timeout两种模式（一般建议使用interval模式，定时更准确且不会太占用资源）；
 * 		5.可在Timer运行过程中随时查看Timer的运行信息。
 * 作者：konger123 （随枫的落叶 konger@126.com）
 * gitee：https://gitee.com/konger123/Timer
 +-------------------------------------------------------------------
 * @version    1.0.0
 * @since      2020.09.08
 * @author     konger123 <konger@126.com>
 * @gitee     https://gitee.com/konger123/Timer
 +-------------------------------------------------------------------
 */
var Timer = (function() {
	/**
	 * 初始化Timer
	 * @param options 参数
	 * 		type：'interval',	//Timer类型：timeout | interval。默认interval
	 * 		delay：1000,		//时间间隔，单位：毫秒。默认1000毫秒(1秒)
	 * 		loop：-1,			//循环次数。默认：-1 表示无限循环
	 * 		name：'timer_'+parseInt(Math.random()*1000000000000),	//Timer的名字，默认值'timer_10位随机数'
	 * 		debug：false,		//调试输出开关，设为true时将会在控制台里打印输出日志信息。默认false
	 * 		startOnInit：false,	//是否在初始化后就启动。默认false
	 * @param runFunc 每次调用执行的方法（function或者string）
	 * @param completeFunc 循环执行完毕后的回调函数（function或者string）
	 * @returns {object} Timer对象
	 */
	var Timer = function(options, runFunc, completeFunc) {
		this.defaults = {
			type: 'interval',//Timer类型：timeout | interval。默认interval
			delay: 1000,//时间间隔，单位：毫秒。默认1000毫秒(1秒)
			loop: -1,//循环次数。默认：-1 表示无限循环
			name: 'timer_'+parseInt(Math.random()*1000000000000),//Timer的名字，默认值'timer_10位随机数'
			debug: false,//调试输出开关，设为true时将会在控制台里打印输出日志信息。默认false
			startOnInit: false,//是否在初始化后就启动。默认false
		};
		this.options = extend(this.defaults, options);
		
		if(this.options.type!='interval' && this.options.type!='timeout') {
			throw new Error("Parameter options type is not valid!");
		}
		if(this.options.delay<=0) {
			this.options.delay = 1;
		}
		if(this.options.loop == true) {
			this.options.loop = -1;
		}
		
		this.runFunc = null;
		if(runFunc!=null && runFunc!="") {
			if(typeof runFunc == "string") {
				this.runFunc = function() {
					eval('(' + runFunc + ')');
				}
			} else if(typeof runFunc == "function") {
				this.runFunc = function() {
					runFunc();
				}
			} else {
				console.error("Parameter runFunc is not valid!");
			}
		}
		this.completeFunc = null;
		if(completeFunc!=null && completeFunc!="") {
			if(typeof completeFunc == "string") {
				this.completeFunc = function() {
					eval('(' + completeFunc + ')');
				}
			} else if(typeof completeFunc == "function") {
				this.completeFunc = function() {
					completeFunc();
				}
			} else {
				console.error("Parameter completeFunc is not valid!");
			}
		}
		
		this.running = false;
		this.timerID = null;
		
		this.runCount = 0;
		this.runBeginTime = 0;
		this.runEndTime = 0;
		
		if(this.options.startOnInit) {
			this.start();
		}
	}
	
	//启动
	Timer.prototype.start = function() {
		if(this.running) {
			if(this.options.debug) {
				console.warn("The timer ["+this.options.name+"] is already running.");
			}
			return;
		}
		var _this = this;
		if(_this.runCount == 0) {
			_this.runBeginTime = new Date().getTime();
			
			if(_this.options.debug) {
				console.info("The timer ["+_this.options.name+"] is starting at beginTime: "+_this.runBeginTime+".");
			}
		}
		
		function r() {
			try {
				_this.runFunc();
			} catch(e) {
				console.error(e);
			}
			_this.runCount++;
			
			if(_this.options.debug) {
				console.info("The timer ["+_this.options.name+"] run once. [runCount="+_this.runCount+", loop="+_this.options.loop+", timerID="+_this.timerID+"]");
			}
			
			if(_this.options.loop >= 0) {
				if(_this.runCount >= _this.options.loop) {
					if(_this.options.type == 'interval') {
						clearInterval(_this.timerID);
					}
					if(_this.options.type == 'timeout') {
						clearTimeout(_this.timerID);
					}
					_this.timerID = null;
					_this.running = false;
					
					try {
						_this.completeFunc();
					} catch(e) {
						console.error(e);
					}
					
					_this.runEndTime = new Date().getTime();
					
					if(_this.options.debug) {
						console.info("The timer ["+_this.options.name+"] is runned complete at endTime: "+_this.runEndTime+". Coast time: "+_this.getRunTime()+", runCount=" + _this.runCount);
					}
				} else {
					if(_this.options.type == 'timeout') {
						_this.timerID = setTimeout(r, _this.options.delay);
					}
				}
			} else {
				if(_this.options.type == 'timeout') {
					_this.timerID = setTimeout(r, _this.options.delay);
				}
			}
		}
		
		if(_this.options.type == 'interval') {
			_this.timerID = setInterval(r, _this.options.delay);
		}
		if(_this.options.type == 'timeout') {
			_this.timerID = setTimeout(r, _this.options.delay);
		}
		_this.running = true;
		
		if(_this.options.debug) {
			console.info("The timer ["+_this.options.name+"] is started. [type='"+_this.options.type+"', delay="+_this.options.delay+", loop="+_this.options.loop+", name='"+_this.options.name+"', startOnInit="+_this.options.startOnInit+", timerID="+_this.timerID+"]");
		}
		return _this.timerID;
	}
	
	//停止
	Timer.prototype.stop = function() {
		if(!this.running) {
			//if(this.options.debug) {
			//	console.warn("The timer ["+this.options.name+"] is already stoped.");
			//}
			return;
		}
		if(this.options.type == 'interval') {
			clearInterval(this.timerID);
		}
		if(this.options.type == 'timeout') {
			clearTimeout(this.timerID);
		}
		this.timerID = null;
		this.running = false;
		this.runCount = 0;
		this.runBeginTime = 0;
		this.runEndTime = 0;
		
		if(this.options.debug) {
			console.info("The timer ["+this.options.name+"] is stoped.");
		}
	}
	
	//暂停
	Timer.prototype.pause = function() {
		if(!this.running) {
			//if(this.options.debug) {
			//	console.warn("The timer ["+this.options.name+"] is not running yet.");
			//}
			return;
		}
		
		if(this.options.type == 'interval') {
			clearInterval(this.timerID);
		}
		if(this.options.type == 'timeout') {
			clearTimeout(this.timerID);
		}
		this.timerID = null;
		this.running = false;
		
		if(this.options.debug) {
			console.info("The timer ["+this.options.name+"] is paused.");
		}
	}
	
	//继续
	Timer.prototype.resume = function() {
		this.start();
	}
	
	//重置
	Timer.prototype.reset = function() {
		this.runCount = 0;
		this.runBeginTime = 0;
		this.runEndTime = 0;
		
		if(this.running) {
			this.runBeginTime = new Date().getTime();
			
			if(this.options.debug) {
				console.info("The timer ["+this.options.name+"] is running, reset beginTime: "+this.runBeginTime+".");
			}
		}
		
		if(this.options.debug) {
			console.info("The timer ["+this.options.name+"] is reseted.");
		}
	}
	
	//获取timer的name
	Timer.prototype.getName = function() {
		return this.options.name;
	}
	
	//获取timer的运行状态
	Timer.prototype.isRunning = function() {
		return this.running;
	}
	
	//获取当前运行次数
	Timer.prototype.getRunCount = function() {
		return this.runCount;
	}
	
	//获取运行时间（单位：毫秒）
	Timer.prototype.getRunTime = function() {
		if(this.runBeginTime == 0) {
			return 0;
		}
		var endTime = this.runEndTime || new Date().getTime();
		return endTime - this.runBeginTime;
	}
	
	//获取运行信息（返回对象）
	Timer.prototype.getInfo = function() {
		return {
			type: this.options.type,
			delay: this.options.delay,
			loop: this.options.loop,
			name: this.options.name,
			startOnInit: this.options.startOnInit,
			running: this.running,
			timerID: this.timerID,
			runCount: this.runCount,
			runBeginTime: this.runBeginTime,
			runEndTime: this.runEndTime,
		};
	}
	
	//获取运行信息（返回字符串）
	Timer.prototype.getInfoStr = function() {
		return "{ type: '" + this.options.type + "', delay: " + this.options.delay + ", loop: " + this.options.loop + ", name: '" + this.options.name + "', startOnInit: " + this.options.startOnInit + ", running: " + this.running + ", timerID: " + this.timerID + ", runCount: " + this.runCount + ", runBeginTime: " + this.runBeginTime + ", runEndTime: " + this.runEndTime + " }";
	}
	
	//更新参数（*注意：更新参数不会重置已运行的状态（已运行次数不归0），如果需要重置的话，建议在update之前调用一下reset()方法）
	Timer.prototype.updateOptions = function(options) {
		this.options = extend(this.options, options);
		
		if(this.options.debug) {
			console.info("The timer ["+this.options.name+"] options is updated. [type='"+this.options.type+"', delay="+this.options.delay+", loop="+this.options.loop+", name='"+this.options.name+"', startOnInit="+this.options.startOnInit+"]");
		}
		
		if(this.running) {
			this.pause();
			this.resume();
		}
	}
	
	//销毁
	Timer.prototype.destroy = function() {
		this.stop();
		for(var a in this) {
			delete this[a];
		}
	}
	
	//参数扩展
	var extend = function(o1, o2) {
		var o = new Object();
		if(typeof o1 == 'object') {
			for(var a in o1) {
				o[a] = o1[a];
			}
		}
		if(typeof o2 == 'object') {
			for(var a in o2) {
				o[a] = o2[a];
			}
		}
		return o;
	}
	
	return Timer;
}());